/** Viewport.java
 *
 * @author Somanath
 *
 * class Dependencies: None
 */

package gamepack;

import java.awt.Graphics;
import java.awt.Rectangle;
import java.util.Vector;
import java.util.Enumeration;

// Every Room contains a Viewport, which determines what part
// of the room is visible in the game.
public class Viewport implements Direction {

       // The viewport x,y give postion of viewport wrt topleft corner of Room
       public Rectangle rect;

       // The sprite which is tracked by viewport
       public Sprite s;

    /* |------------------------------------|
       |                                    |<----- Room
       |    |------------------------|      |
       |    |          up            |<------------ Viewport.rect
       |    |      |--------|        |      |
       |    | left |s       |  right |      |
       |    |      |--------|<--------------------- inner box
       |    |         down           |      |
       |----|------------------------|------|       s = Sprite

    /// The offset describe the innerbox within the viewport
    /// and is used for scrolling. If the sprite moves out of the
    /// innerbox the viewport scrolls automatically such that
    /// the sprite stays inside the innerbox. */
       public int left,right,up,down;

       public Room room;

       public Viewport(Room room) {
           this.room = room;
           if( room != null ) {
              rect = new Rectangle(0,0,room.getWidth(),room.getHeight());
              left = right = rect.width/4;
              up = down = rect.height/4;
           }
       }

       public Viewport(Room room,Rectangle r,int ...innerbox) { // expected 4 args in order >> int left, int right, int up, int down
           this.room = room;
           if( r == null ) throw new GamePackException("Viewport rect not specified");
           rect = new Rectangle(r);
           if (innerbox.length >= 4) down = innerbox[3];
           if (innerbox.length >= 3) up = innerbox[2];
           if (innerbox.length >= 2) right = innerbox[1];
           if (innerbox.length >= 1) left = innerbox[0];
       }

       // Tells if the viewport can move 'dist' pixels in direction 'dir'
       // Returns a number between 0 - dist
       // private as there is no check for room == null
       private int howFar(int dir, int dist) {
            int maxDist = 0;
            switch( dir ) {
                case WEST:  maxDist = rect.x; break;
                case EAST:  maxDist = room.getWidth()-(rect.x + rect.width);  break;
                case NORTH: maxDist = rect.y;  break;
                case SOUTH: maxDist = room.getHeight()-(rect.y + rect.height); break;
            }
            return ( dist < maxDist ) ? dist : maxDist;
       }

       private void move(int dir,int dist) {

            int vx=0,vy=0;
            switch( dir ) {
                case NORTH: vy=-dist; break;
                case SOUTH: vy=+dist; break;
                case WEST:  vx=-dist; break;
                case EAST:  vx=+dist; break;
            }
            rect.x += vx;
            rect.y += vy;
       }

       // Updates the viewport port that sprite s is inside
       // viewport, also moves viewport is sprite moves outside
       // offsets left/right/up/down.
       public void update() {
          //System.out.println("Inside Viewport.update() room=" + room + ":" + s);
           if( room != null && s != null) {

               // if sprite is on left of innerbox
               if( s.x < (rect.x+left) ) {
                   int leftDist = (rect.x+left) - s.x;
                   leftDist = howFar( WEST, leftDist );
                   if( leftDist != 0 ) { move( WEST, leftDist );  }
               }
               if ( s.x > (rect.x+rect.width-(left) )) {
                   int rightDist = s.x - (rect.x+rect.width-right);
                   rightDist = howFar( EAST, rightDist);
                   if( rightDist != 0 ) {move( EAST, rightDist); }
               }
               if ( s.y < (rect.y+up)){
                   int upDist = (rect.y+up) - s.y;
                   upDist = howFar( NORTH, upDist );
                   if( upDist != 0 ) { move( NORTH, upDist );  }
               }
               if ( s.y > (rect.y+rect.height-down )) {
                   int downDist = s.y - (rect.y+rect.height-down );
                   downDist = howFar( SOUTH, downDist);
                   if( downDist != 0 ) {
                        move( SOUTH, downDist);
                   } //System.out.println("If sprite below inner rect");
               }
           }
       }
}